Aprendiendo de los fallos: Docker en la Raspberry Pi



Llevo unos días leyendo mucho acerca de Docker.

Después de instalar Docker en Debian Jessie en tres VMs, estuve haciendo pruebas con Docker Swarm y todo fue increíblemente rápido y sencillo (tengo pendiente publicar los detalles).

Esta tarde, sin embargo, las cosas no me han salido tan bien... Pero claro, estaba jugando con Docker en la Raspberry Pi. El problema con el que me encuentro una y otra vez es que, tanto en los libros como en los blogs que leo, se supone que la plataforma es x64, y no ARM. Es normal, ya que la Docker -en principio- sólo está soportado en esa plataforma...pero no deja de ser un poco fastidioso.

¿Y qué pasa cuando quieres probar alguna cosa sobre la RPi? Que la imagen base que se cita en el Dockerfile no está disponible para ARM (o no es fácil de encontrar, al menos). Así que empiezas a probar cosas un poco a lo loco y puede acabar siendo algo desesperante.

Para evitar que otros con problemas parecidos se queden en el camino, voy a explicar qué pasos he ido dando hasta tener corriendo mi primera imagen con Nginx (xaviaznar/nginx:0.1)

En primer lugar, resulta que Debian no dispone de una imagen oficial en DockerHub para la plataforma ARM (https://hub.docker.com/_/debian/), así que no puedes usarla como imagen base. Lo mismo sucede con otra de las imágenes base habituales de los ficheros Dockerfile: Ubuntu. Después de haber leído recientemente que Docker está pasando de imágenes con base Ubuntu  (aprox 140MB) a usar Alpine (aprox 5MB) debido a su menor tamaño, he saltado de alegría cuando he visto que hay una imagen de los amigos de Hypriot basada en Alpine (hypriot/rpi-alpine-scratch).

He creado un Dockerfile con la intención de crear una imagen con Nginx y la construcción ha fallado porque no encontraba apt-get. Me ha parecido muy raro, porque por algún motivo pensaba que Alpine también tenía como base Debian. Pero resulta que no es así. Y ya tengo bastantes problemas con lo poco de linux que sé como para meterme con los comandos de una nueva distribución... Así que mi gozo en un pozo.

Un poco por suerte, he encontrado un artículo en el que se apuntaba a la imagen resin/raspbian como una de las pocas "semi-oficiales" que hay en las que poder confiar (ver el punto 3 de este artículo de Alex Ellis). A partir de ahí, el resto ha sido más o menos fácil.

La construcción de la imagen ha funcionado a la primera:

$ docker build -t xaviaznar/nginx:0.1 .

He lanzado mi primer intento de contenedor y me he asombrado con el siguiente mensaje:

$ docker run -d --name webserver xaviaznar/nginx
Unable to find image 'xaviaznar/nginx:latest' locally
Pulling repository docker.io/xaviaznar/nginx
docker: Error: image xaviaznar/nginx:latest not found.
See 'docker run --help'.

Después me he dado cuenta de que he construido la imagen con la etiqueta "0.1", pero al lanzar el contenedor no he indicado ninguna etiqueta concreta, con lo que Docker ha asumido "latest". Pero mi imagen no tiene asociada ninguna etiqueta "latest". A continuación la ha buscado en DockerHub, donde tampoco la ha encontrado.

Todo correcto... una vez que entiendes qué estás haciendo mal .

Una vez corregido el comando para lanzar el contenedor usando la etiqueta correcta de la imagen, el contenedor ha arrancado.

$ docker run -d --name webserver xaviaznar/nginx:0.1

¿Ves el fallo? Resulta que he lanzado el comando, se ha arrancado el contenedor, pero cuando he intentado conectar con el servidor web, me he dado cuenta que no sabía en qué puerto estaba escuchando.

Tirando del conocimiento adquirido estos días, he lanzado docker ps y docker inspect webserver para intentar averiguar en qué puerto estaba sirviendo Nginx en el contenedor las páginas web. Pero no se indicaba ningún puerto del host en la salida de los comandos anteriores...

De nuevo, todo correcto, porque el problema ha sido que no he indicado en el comando docker run ni un mapeo de puertos explícito -como -p 80:80, por ejemplo-, ni implícito, dejando que Docker asignara un puerto libre mediante docker run -d -P ..., etc.

También he intentado conectarme al contenedor mediante docker exec y revisar directamente el puerto especificado en la configuración de Nginx, pero tampoco lo he conseguido. Al lanzar el comando no obtenía ninguna respuesta por parte del contenedor, como si se hubiera quedado "colgado":

$ docker exec webserver /bin/bash

De nuevo, fallo mío, ya que he lanzado el proceso pero no he indicado que quería hacerlo en modo "interactivo", por lo que no obtenía ningún tipo de salida.

El comando correcto -después de consultar la documentación oficial del comando en el sitio de Docker- ha sido:

$ docker exec -it webserver /bin/bash

Después de solucionar todos estos errores, al intentar lanzar de nuevo el contenedor, Docker me ha indicado que el nombre webserver ya estaba en uso, así que he eliminado el contenedor y lo he lanzado, esta vez sí, con la opción -P. A continuación, mediante docker ps, he obtenido el puerto publicado para el contenedor:

CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
8c5f0bbfb55f        xaviaznar/nginx:0.1    "/usr/bin/entry.sh /b"   About an hour ago   Up About an hour    0.0.0.0:32768->80/tcp    webserver

Lecciones aprendidas

Lo importante de este artículo no son los pasos concretos que he seguido hasta conseguir poner en marcha el contenedor, sino el proceso: ensayo y error.

Hay que probar cosas, desviarse un poco del camino marcado y buscar mucho en Google. Siempre que sea posible, acudir a la documentación oficial (sintaxis de los comandos, etc) y tampoco está de más conocer cómo funciona el producto por dentro (como lo de la etiqueta latest o el que se busca la imagen en DockerHub si no se encuentra localmente).

Cuando las cosas no funcionen a la primera, o como indica el manual, no seguir enfrentándose al problema de frente: optar por buscar otras vías. Hay que preguntarse qué información necesitas y cómo puedes conseguirla (docker ps, docker inspect, docker exec para conectar al contenedor y averiguar el puerto de Nginx, etc.)

Pero quizás lo más importante es no desfallecer, nunca darse por vencido y sobretodo DISFRUTAR aprendiendo. Porque aprender consiste, sobretodo, en equivocarse.

Si te gustan los videojuegos, te recomiendo este artículo en el que se indica cómo extraer grandes lecciones para la vida de la diversión que te aporta jugar: Qué puedes aprender de los videojuegos

Comentarios